from Ft.Xml.Sax import ContentHandler, CreateParser
from myelin.Ns import XML_NS, MYELINS

YES = set(['1','yes','true'])

#class Description:
#    
#    def __init__(self, uri, title):
#        self.uri = uri
#        self.title = title
#        self.body = u''

class TextIndex:
    
    def __init__(self,key,descUri):
        self.key = key
        self.descUri = descUri

class Config:
    
    def __init__(self, type, cacheable):
        self.type = type
        self.cacheable = cacheable
        self.textIndices = {}
        self.defaultTextIndices = {}
        self.params = {}
        
    def asXml(self):
        return Serializer().serialize(self).xml()
    
    def asAmara(self):
        return Serializer().serialize(self)
    
    def asDom(self):
        from Ft.Xml import Parse
        return Parse(Serializer().serialize(self).xml())
        
class RootContentHandler(ContentHandler):
    parent = None
    def __init__(self, parser):
        self.parser = parser
        
class ContentHandler(ContentHandler):
    currentElement = None
    
    def __init__(self, parent):
        self.parent = parent
        self.parser = parent.parser
            
    def endElementNS(self, (uri, localName), qualifiedName):
        if getattr(self.parent,'currentElement',None) == (uri,localName):
            self.parent.parser.setContentHandler(self.parent)

class ConfigHandler(ContentHandler):
    config = None
    
    def startElementNS(self, name, qname, atts):

        if name == (MYELINS,'TextSearchService'):
            #print qname, atts
            self.config = Config(
                atts.get((None,'type')),
                atts.get((None,'cacheable'),'').lower() in YES
            )
            self.parser.setContentHandler(
                TextSearchServiceHandler(
                    self,
                    self.config
                )
            )
            self.currentElement = name
    
            
class TextSearchServiceHandler(ContentHandler):
    
    def __init__(self, parent, config):
        ContentHandler.__init__(self,parent)
        self.config = config        
   
    def startElementNS(self, name, qname, atts):

        if name == (MYELINS,'TextIndex'):
            #print qname, atts
            uri = atts[(None,'uri')]                
            index = TextIndex(
                atts[(None,'key')],
                atts.get((None,'desc-uri'))
            )
            if atts.get((None,'default')) in YES:
                self.config.defaultTextIndices[uri] = index
            self.config.textIndices[uri] = index                
            self.parser.setContentHandler(
                TextIndexHandler(
                    self,
                    index,
                    uri
                )
            )
            self.currentElement = name
            
        elif name == (MYELINS,'Params'):
            self.config.params.update(atts)
    

class TextIndexHandler(ContentHandler):
    def __init__(self, parent, index, uri):
        ContentHandler.__init__(self,parent)
        self.index = index
        self.uri = uri
        
#    def startElementNS(self, name, qname, atts):
#        if name == (MYELINS, "Description"):
#            #print name, atts
#            desc = Description(                
#                atts.get((None,'uri')),
#                atts.get((None,'title'))         
#            )
#            lang = atts.get((XML_NS,'lang'))
#            self.index.descriptions[lang] = desc
#            self.parser.setContentHandler(
#                DescriptionHandler(
#                    self,
#                    desc,
#                    lang
#                )
#            )
#            self.currentElement = name
#            
#class DescriptionHandler(ContentHandler):
#    
#    def __init__(self, parent, desc, lang):
#        ContentHandler.__init__(self, parent)
#        self.desc = desc
#        self.lang = lang
#        
#    def characters(self, content):
#        self.desc.body += content       
    

class Serializer:
    
    def deserialize(self, source):
                
        parser = CreateParser()
        handler = ConfigHandler(RootContentHandler(parser))
        
        parser.setContentHandler(handler)
        
        #from cStringIO import StringIO
        parser.parse(source)
        
        return handler.config
    
    def serialize(self, config):
        import amara
        doc = {
            u'type' : config.type
        }
        if config.cacheable:
            doc[u'cacheable'] = u'1'
            
        doc = amara.create_document(
            u'TextSearchService',MYELINS,
            attributes = doc
        )
        
        dc = doc.childNodes[0].xml_create_element
        da = doc.childNodes[0].xml_append
        
        if config.params:
            ns = {}
            atts = {}
            c = 0
            for q,v in config.params.iteritems():
                if q[0]:
                    if q[0] in ns:
                        qname = ns.get(q[0])
                    else:
                        qname = u'ns%s:%s' % (c,q[1])
                        ns[q[0]] = qname
                        c += 1
                    atts[(qname,q[0])] = v
                else:
                    atts[q[1]] = v
                    
            da(dc(
                u'Params', MYELINS,
                attributes = atts
            ))
        
        defaultTextIndices = config.defaultTextIndices
        
        for u,g in config.textIndices.iteritems():
            atts = {
                u'key' : g.key,
                u'uri' : u,                
            }
            if g.descUri:
                atts[u'desc-uri'] = g.descUri
            if u in defaultTextIndices:
                atts[u'default'] = u'1'
                
            da(dc(
                u'TextIndex', MYELINS,
                attributes = atts
            ))
            #ec = el.xml_create_element
            #ea = el.xml_append
            #for l, i in g.descriptions.iteritems():
            #    ea(ec(
            #        u'Description', MYELINS,
            #        attributes = {
            #            (u'xml:lang',XML_NS): l,
            #            u'title': i.title,
            #            u'uri': i.uri,
            #        },
            #        content = i.body
            #    ))
                
        return doc
    
if __debug__:
    def Test(src):
        from Ft.Xml.Lib.TreeCompare import TreeCompare
        from cStringIO import StringIO
        doc = Serializer().deserialize(StringIO(src))
        doc = Serializer().serialize(doc).xml()        
        TreeCompare(src,doc)
        
        
    def GetTestCases():
        return [
            """<?xml version="1.0" encoding="UTF-8"?>
<TextSearchService
  xmlns='http://xmlns.heustics.org/schema/myelin/0.1/'
  cacheable='1'
  type='http://xmlns.heustics.org/ontology/myelin/0.1/TextSearchService'
  >
    <TextIndex key='profiles-archived' uri='urn:uuid:2ee4a4e5-3908-4b5c-b250-279cc075ff5c'
        desc-uri='http://test.org/test1'/>
    <TextIndex key='profiles-unpublished' uri='urn:uuid:36f286d8-c194-4035-b9f0-62bed024944f'
        desc-uri='http://test.org/test2'/>
    <TextIndex key='site' uri='urn:uuid:c268953c-7e73-45ba-b3d2-6f882fc005a0'
        desc-uri='http://test.org/test3'/>
    <TextIndex key='corporate' uri='urn:uuid:e2b4dd9a-79f4-4cef-98e1-416b628d8d36'
        desc-uri='http://test.org/test4'/>
    
    <Foo><Bar>This should be ignored.</Bar></Foo>
    
</TextSearchService>""",
        ]
         
    def TestCases(cases=None):
        if not cases:
            cases = GetTestCases()
        for i in cases:
            Test(cleanup(i))
            
    def TestDeserialize(src=None):
        if not src:
            src = GetTestCases()[0]
        from cStringIO import StringIO
        return Serializer().deserialize(StringIO(src))
            
    def cleanup(src):
        return '>'.join('><'.join(''.join(' '.join(filter(None,src.split(' '))).split('\n')).split('> <')).split(' >'))